﻿/* DataClass
#-------------------------------------------------------------------------------
# Name:        RotatePlate - Class that can rotate a plate horizontal
#
# Contains:    Function to rotate the the plate straight
#              also has 
#              
#
# Requires:    Visual Studio 2010 and up.
#
# Author:      Roy Scheefhals, Martijn Koopman ( basis idee van Team 10 gebruikt)
#
# Created:     03-03-2012
#-------------------------------------------------------------------------------
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LibraryCS {
    public static class RotatePlate {


        public static VImage rotate(VImage inputImage) {
            // Calculate angle
            float degAngle = (float)findAngle(inputImage);

            // Create rotated graphics
            Bitmap rotatedBitmap = new Bitmap(inputImage.Width, inputImage.Height);
            Graphics g = Graphics.FromImage(rotatedBitmap);

            // Place rotation point in center
            g.TranslateTransform((float)inputImage.Width / 2, (float)inputImage.Height / 2);

            // rotate
            g.RotateTransform(degAngle);

            // Shift image to origin
            g.TranslateTransform(-(float)inputImage.Width / 2, -(float)inputImage.Height / 2);

            //draw passed in image onto graphics object
            inputImage.ApplyPixelChanges();
            g.DrawImage(inputImage.localBitmap, new Point(0, 0));

            // Create VImage
            VImage rotatedImage = new VImage(rotatedBitmap);

            // Rotate blob info
            rotatedImage.blob = rotateBlob(inputImage.blob, degAngle);

            Console.Out.WriteLine("Input blob: " + inputImage.blob);
            Console.Out.WriteLine("Rotated blob: " + rotatedImage.blob);

            return rotatedImage;
        }


        //Finds the angle that the license plate needs to rotate
        private static double findAngle(VImage inputImage) {
            double angle1 = 0.0, angle2 = 0.0;
            double radian = 0.0;

            // Calculate angle of upper side
            int dY = inputImage.blob.topLeft.Y - inputImage.blob.topRight.Y;
            int dX = inputImage.blob.topRight.X - inputImage.blob.topLeft.X;
            if (dX != 0) {
                radian = (double)dY / (double)dX;
                angle1 = (float)((radian * (180 / Math.PI)));
            }

            // Calculate angle of lower side
            dY = inputImage.blob.bottomLeft.Y - inputImage.blob.bottomRight.Y;
            dX = inputImage.blob.bottomRight.X - inputImage.blob.bottomLeft.X;
            if (dX != 0) {
                radian = (double)dY / (double)dX;
                angle2 = (float)((radian * (180 / Math.PI)));
            }

            return (angle1 + angle2) / 2;
        }

        // Rotate a blob with by a given angle
        private static Blob rotateBlob(Blob oldBlob, double angle) {
            Point centroid = new Point((oldBlob.maxx - oldBlob.minx) /2, (oldBlob.maxy - oldBlob.miny) / 2);

            Blob newBlob = new Blob();
            // Calculate new corner position
            newBlob.topLeft = rotatePointAroundCentroid(oldBlob.topLeft, centroid, angle);
            newBlob.topRight = rotatePointAroundCentroid(oldBlob.topRight, centroid, angle);
            newBlob.bottomLeft = rotatePointAroundCentroid(oldBlob.bottomLeft, centroid, angle);
            newBlob.bottomRight = rotatePointAroundCentroid(oldBlob.bottomRight, centroid, angle);

            // Calculate new bounding box
            newBlob.minx = (newBlob.topLeft.X > newBlob.bottomLeft.X) ? newBlob.topLeft.X : newBlob.bottomLeft.X;
            newBlob.miny = (newBlob.topLeft.Y > newBlob.topRight.Y) ? newBlob.topLeft.Y : newBlob.topRight.Y;
            newBlob.maxx = (newBlob.topRight.X < newBlob.bottomRight.X) ? newBlob.topRight.X : newBlob.bottomRight.X;
            newBlob.maxy = (newBlob.bottomLeft.Y < newBlob.bottomRight.Y) ? newBlob.bottomLeft.Y : newBlob.bottomRight.Y;

            newBlob.amountOfPixels = oldBlob.amountOfPixels;

            return newBlob;
         }

        // Rotate a point around another point
        private static Point rotatePointAroundCentroid(Point oldPoint, Point centroid, double degangle) {
            double radianAngle = (2 * Math.PI * degangle) / 360.0;
            double sin = Math.Sin(radianAngle);
            double cos = Math.Cos(radianAngle);

            double oldX = oldPoint.X;
            double oldY = oldPoint.Y;
            double centerX = centroid.X;
            double centerY = centroid.Y;

            Point newPoint = new Point(oldPoint.X - centroid.X, oldPoint.Y - centroid.Y);

            int newX = (int)Math.Round((cos * newPoint.X - sin * newPoint.Y));
            int newY = (int)Math.Round(((sin * newPoint.X) + cos * newPoint.Y));

            newPoint.X = newX + centroid.X;
            newPoint.Y = newY + centroid.Y;

            return newPoint;
         }
    }
}
